from datetime import datetime

import bleach
from markdown import markdown
from werkzeug.security import check_password_hash, generate_password_hash

from . import db
from flask_login import UserMixin, AnonymousUserMixin


class TAuthority(db.Model):
    __tablename__ = 't_authority'

    authority_id = db.Column(db.Integer, primary_key=True)
    authority_name = db.Column(db.String(20))


class TAuthorityCharacter(db.Model):
    __tablename__ = 't_authority_character'

    authority_id = db.Column(db.ForeignKey('t_authority.authority_id'), primary_key=True, nullable=False)
    character_id = db.Column(db.ForeignKey('t_character.character_id'), primary_key=True, nullable=False, index=True)
    authority_startime = db.Column(db.Date)
    authorith_endtime = db.Column(db.Date)

    authority = db.relationship('TAuthority', primaryjoin='TAuthorityCharacter.authority_id == TAuthority.authority_id',
                                backref='t_authority_characters')
    character = db.relationship('TCharacter', primaryjoin='TAuthorityCharacter.character_id == TCharacter.character_id',
                                backref='t_authority_characters')


class TCharacter(db.Model):
    __tablename__ = 't_character'

    character_id = db.Column(db.Integer, primary_key=True)
    character_name = db.Column(db.String(20))


class TPassage(db.Model):
    __tablename__ = 't_passage'

    passage_id = db.Column(db.String(20), primary_key=True)
    passage_publicer = db.Column(db.ForeignKey('t_user.user_id'), nullable=False, index=True)
    passage_name = db.Column(db.String(100), nullable=False, index=True)
    passage_publictime = db.Column(db.DateTime, nullable=False, server_default=db.FetchedValue())
    passage_somesource = db.Column(db.String(50), nullable=False)

    t_user = db.relationship('TUser', primaryjoin='TPassage.passage_publicer == TUser.user_id', backref='t_passages')


class TPassageSource(db.Model):
    __tablename__ = 't_passage_source'

    passage_id = db.Column(db.ForeignKey('t_passage.passage_id'), primary_key=True)
    passage_source_md = db.Column(db.String)
    passage_source_html = db.Column(db.String)

    @staticmethod
    def on_changed_body(target, value, oldvalue, initiator):
        allowed_tags = ['a', 'abbr', 'acronym', 'b', 'blockquote', 'code',
                        'em', 'i', 'li', 'ol', 'pre', 'strong', 'ul', 'h1',
                        'h2', 'h3', 'h4', 'p']
        target.passage_source_html = bleach.linkify(
            bleach.clean(markdown(value, output_format='html'), tags=allowed_tags))


db.event.listen(TPassageSource.passage_source_md, 'set', TPassageSource.on_changed_body)


class TUser(db.Model, UserMixin):
    __tablename__ = 't_user'

    user_id = db.Column(db.String(20), primary_key=True)
    user_name = db.Column(db.String(40), unique=True)
    user_password = db.Column(db.String(128))
    user_lastseen = db.Column(db.DateTime)

    def __repr__(self):
        return '<User %r>' % self.username

    def get_id(self):
        return str(self.user_id)

    def not_password(self):
        raise AttributeError("password is not readable!")

    def password(self, user_password):
        self.user_password = generate_password_hash(user_password)

    def verify_password(self, user_password):
        return check_password_hash(self.user_password, user_password)

    def can(self, permissions):
        return False

    def is_admin(self):
        return False

    def ping(self):
        self.user_lastseen = datetime.utcnow()
        db.session.add(self)


class AnonymousUser(AnonymousUserMixin):
    def can(self):
        return False

    def is_admin(self):
        return False


class Permission:
    FOLLOW = '0x01'
    COMMENT = '0x02'
    WRITE_ARTICLES = '0x04'
    MODERATE_COMMENTS = '0x08'
    ADMINISTERT = '0x80'


class TUserInformation(db.Model):
    __tablename__ = 't_user_information'

    user_id = db.Column(db.ForeignKey('t_user.user_id'), primary_key=True)
    user_truename = db.Column(db.String(20))
    user_sex = db.Column(db.String(2))
    user_email = db.Column(db.String(20), index=True)
    user_phonenumber = db.Column(db.String(20), index=True)
    user_signuptime = db.Column(db.DateTime)
    user_birthday = db.Column(db.Date)
    user_profession = db.Column(db.String(20))
    user_units = db.Column(db.String(50))
    user_location = db.Column(db.String(50))
    user_about = db.Column(db.String(128))


class TUserCharacter(db.Model):
    __tablename__ = 't_user_character'

    character_id = db.Column(db.ForeignKey('t_character.character_id'), primary_key=True, nullable=False)
    user_id = db.Column(db.ForeignKey('t_user.user_id'), primary_key=True, nullable=False, index=True)
    character_startime = db.Column(db.Date)
    character_endtime = db.Column(db.Date)

    character = db.relationship('TCharacter', primaryjoin='TUserCharacter.character_id == TCharacter.character_id',
                                backref='t_user_characters')
    user = db.relationship('TUser', primaryjoin='TUserCharacter.user_id == TUser.user_id', backref='t_user_characters')


class TUserDoforPassage(db.Model):
    __tablename__ = 't_user_dofor_passage'

    user_id = db.Column(db.ForeignKey('t_user.user_id'), primary_key=True, nullable=False)
    passage_id = db.Column(db.ForeignKey('t_passage.passage_id'), primary_key=True, nullable=False, index=True)
    do_grades = db.Column(db.String(50))

    passage = db.relationship('TPassage', primaryjoin='TUserDoforPassage.passage_id == TPassage.passage_id',
                              backref='t_user_dofor_passages')
    user = db.relationship('TUser', primaryjoin='TUserDoforPassage.user_id == TUser.user_id',
                           backref='t_user_dofor_passages')


t_v_passage = db.Table(
    'v_passage',
    db.Column('passage_id', db.String(20)),
    db.Column('passage_publicer', db.String(20)),
    db.Column('passage_name', db.String(100)),
    db.Column('passage_publictime', db.DateTime, server_default=db.FetchedValue()),
    db.Column('passage_source', db.String)
)
